package com.gagan.tplmatcher;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author gagan.goku@gmail.com
 */
public class TemplateTree {
  public static String escapePattern(String pattern) {
    String p = pattern;
    p = p.replaceAll("\\[", "\\\\[");
    p = p.replaceAll("\\]", "\\\\]");
    p = p.replaceAll("\\{", "\\\\{");
    p = p.replaceAll("\\}", "\\\\}");
    p = p.replaceAll("\\?", "\\\\?");
    p = p.replaceAll("\\(", "\\\\(");
    p = p.replaceAll("\\)", "\\\\)");
    p = p.replaceAll("\\|", "\\\\|");

    p = p.replaceAll("\\\\\\{\\\\\\{", "{{");
    p = p.replaceAll("\\\\\\}\\\\\\}", "}}");

    p = p.replaceAll("\\s+\\n", "\n");

    p = p.replaceAll("\\{\\{#REPEAT\\}\\}\n", "{{#REPEAT}}");
    p = p.replaceAll("\\{\\{/REPEAT\\}\\}\n", "{{/REPEAT}}");

    return p;
  }

  // TODO(gagan): Patterns are not safe wrt dangling { in the pattern.
  public static final String EMPTY_CAPTURE = "\\{\\{EMPTY\\}\\}";
  public static final String EMPTY_REGEX = "()";

  public static final String NON_TAGBEGIN_STAR = "\\{\\{NON_TAGBEGIN_STAR\\}\\}";
  public static final String NON_TAGBEGIN_STAR_REGEX = "([^<]*)";

  public static final String NON_QUOTE_STAR = "\\{\\{NON_QUOTE_STAR\\}\\}";
  public static final String NON_QUOTE_STAR_REGEX = "([^\"]*)";

  public static final String OR  = "\\|\\|";

  public static final String ALTERNATION = "\\{\\{#ALT\\}\\}([^{]*)\\{\\{/ALT\\}\\}";
  public static final String QUOTE_VAR = "\\{\\{[a-zA-Z_]+\\}\\}";

  public static final String DATA_BIND_ID = "data-bind-id=\"[^\"]*\"";

  public static List<String> parseTemplate(String tpl) {
    tpl = escapePattern(tpl);

    tpl = tpl.replaceAll(EMPTY_CAPTURE, EMPTY_REGEX);
    tpl = tpl.replaceAll(NON_TAGBEGIN_STAR, NON_TAGBEGIN_STAR_REGEX);
    tpl = tpl.replaceAll(NON_QUOTE_STAR, NON_QUOTE_STAR_REGEX);

    tpl = tpl.replaceAll(QUOTE_VAR, NON_QUOTE_STAR_REGEX);
    tpl = tpl.replaceAll(DATA_BIND_ID, "data-bind-id=\"([^\"]*)\"");
    tpl = tpl.replaceAll(OR, "|");

    Pattern alt = Pattern.compile(ALTERNATION, Pattern.DOTALL | Pattern.MULTILINE);
    while (true) {
      Matcher m = alt.matcher(tpl);
      if (!m.find()) {
        break;
      }

      tpl = tpl.substring(0, m.start(0)-1) + "(?:" + m.group(1) + ")" +
          tpl.substring(m.end());
    }

    List<String> regex = new ArrayList<String>();
    regex.add(tpl);
    int j = 0;
    while (j < regex.size()) {
      tpl = regex.remove(j);

      int group = 0;
      int start = -1, prev = 0;
      boolean changed = false;

      for (int i = 0; i < tpl.length()-10; i++) {
        if (tpl.substring(i, i+11).equals("{{#REPEAT}}")) {
          if (group++ == 0) {
            start = i;
          }
        } else if (tpl.substring(i, i+11).equals("{{/REPEAT}}")) {
          if (--group == 0) {
            // Extract this.
            String before = tpl.substring(prev, start);
            String match = tpl.substring(start+11, i);
            String after = tpl.substring(i+11);

            if (!before.isEmpty()) {
              regex.add(j++, before);
            }
            if (!match.isEmpty()) {
              regex.add(j++, match);
            }
            if (!after.isEmpty()) {
              regex.add(j++, after);
            }
            prev = i+12;
            changed = true;
            break;
          }
        }
      }
      if (changed) {
        j = 0;
      } else {
        regex.add(j++, tpl);
      }
    }

    String content = "";
    for (String s : regex) {
      content += s;
    }

    return regex;
  }
}
